package com.my.fo.util;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.util.StrUtil;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.asf.AsfFileReader;
import org.jaudiotagger.audio.exceptions.CannotReadException;
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.audio.flac.FlacFileReader;
import org.jaudiotagger.audio.generic.AudioFileReader;
import org.jaudiotagger.audio.mp3.MP3FileReader;
import org.jaudiotagger.audio.mp4.Mp4FileReader;
import org.jaudiotagger.audio.ogg.OggFileReader;
import org.jaudiotagger.audio.wav.WavFileReader;
import org.jaudiotagger.tag.FieldKey;
import org.jaudiotagger.tag.Tag;
import org.jaudiotagger.tag.TagException;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;

public class MusicOrganizationUtil {

    /**
     * 获取音乐文件读取器
     * @param musicFile 音乐文件
     * @return 音乐文件读取器
     */
    public static AudioFile getAudioFIleReader(File musicFile) {
        String suffix = FileUtil.getSuffix(musicFile);
        if (musicFile == null || !musicFile.exists() || suffix == null) return null;
        AudioFileReader audioFileReader = switch (suffix) {
            case "asf" -> new AsfFileReader();
            case "flac" -> new FlacFileReader();
            case "mp3" -> new MP3FileReader();
            case "ogg" -> new OggFileReader();
            case "wav" -> new WavFileReader();
            default -> null;
        };
        if (audioFileReader == null) return null;
        try {
            return audioFileReader.read(musicFile);
        } catch (CannotReadException | InvalidAudioFrameException | TagException | ReadOnlyFileException | IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static List<File> loopMusicFile(String path, String defOutput, FileFilter filter) {
        return loopMusicFile(new File(path), defOutput, filter);
    }

    public static List<File> loopMusicFile(File file, String defOutput, FileFilter filter) {
        final List<File> fileList = new ArrayList<>();
        if (!FileUtil.exist(file)) return fileList;
        if (FileUtil.isFile(file)) {
            if (filter == null || filter.accept(file)) fileList.add(file);
            return fileList;
        }
        try {
            Files.walkFileTree(file.toPath(), new SimpleFileVisitor<>() {
                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                    if (StrUtil.equals(dir.toFile().getName(), defOutput)) return FileVisitResult.SKIP_SUBTREE;
                    return super.preVisitDirectory(dir, attrs);
                }

                @Override
                public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
                    final File file = path.toFile();
                    if (filter == null || filter.accept(file)) fileList.add(file);
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (final IOException e) {
            throw new IORuntimeException(e);
        }
        return fileList;
    }

    /**
     * 判断是不是Window系统
     * @return
     */
    public static boolean isWindows() {
        return System.getProperties().getProperty("os.name").toUpperCase().contains("WINDOWS");
    }

    /**
     * 处理在Window系统不适配的各种字符
     */
    public static String handleWindowsPathChat(String path) {
        return isWindows() ? path.replaceAll(":", "：") : path;
    }

    /**
     * 根据目录结构获取最终目录
     * @param outputSrc 输出目录
     * @param orgStruct 目录结构
     * @param musicFile 音乐文件
     * @return 最早目录
     */
    public static String getMusicFileByOrgStruct(String outputSrc, String orgStruct, File musicFile) {
        // 专辑：ALBUM；艺术家：ARTIST；标题：TITLE；年份：YEAR；专辑艺术家：ALBUM_ARTIST；源文件名称：FILE_NAME；后缀：SUFFIX
        String suffix = FileUtil.getSuffix(musicFile);
        String fileName = musicFile.getName();
        AudioFile audioFile = getAudioFIleReader(musicFile);
        if (audioFile == null) return null;
        Tag tag = audioFile.getTag();
        String album = tag.getFirst(FieldKey.ALBUM);
        String artist = tag.getFirst(FieldKey.ARTIST);
        String title = tag.getFirst(FieldKey.TITLE);
        String year = tag.getFirst(FieldKey.YEAR);
        String albumArtist = tag.getFirst(FieldKey.ALBUM_ARTIST);
        String outOrgStruct = orgStruct.replaceAll("\\{ALBUM\\}", album).replaceAll("\\{ARTIST\\}", artist).replaceAll("\\{TITLE\\}", title)
                .replaceAll("\\{YEAR\\}", year).replaceAll("\\{ALBUM_ARTIST\\}", albumArtist).replaceAll("\\{FILE_NAME\\}", fileName).replaceAll("\\{SUFFIX\\}", suffix);
        if (!outOrgStruct.endsWith("." + suffix)) outOrgStruct += "." + suffix;
        ExpressionParser parser = new SpelExpressionParser();
        TemplateParserContext templateParserContext = new TemplateParserContext();
        outOrgStruct = parser.parseExpression(outOrgStruct, templateParserContext).getValue(String.class);
        return Paths.get(outputSrc, handleWindowsPathChat(outOrgStruct)).toString();
    }

    public static void main(String[] args) {
        System.out.println(getMusicFileByOrgStruct("D:\\Music\\",
                "{ALBUM}/#{{ARTIST}.replace('')}/{TITLE}-{ARTIST}.{SUFFIX}", new File("C:\\Users\\my\\Downloads\\邻居.mp3")));;
    }

}
